AuntieDialogPete Gontier
|
resource type |
what is it? |
AuntieDialog behavior |
|
||
|
dialog template |
fully supported in nearly the same way as Dialog Manager |
|
dialog item list |
fully supported in nearly the same way as Dialog Manager |
|
control template |
fully supported in nearly the same way as Dialog Manager |
|
new-style |
fully supported in nearly the same way as Dialog Manager |
|
||
|
old-style |
ignored in favor of |
|
dialog color table |
ignored in favor of maximizing Appearance-savviness |
|
dialog template extension |
ignored in favor of maximizing Appearance-savviness |
|
alert template |
not supported; AuntieDialog does not make the distinction between alerts and dialogs |
|
alert template extension |
not supported; AuntieDialog does not make the distinction between alerts and dialogs |
|
alert item color and text style table |
not supported; AuntieDialog does not make the distinction between alerts and dialogs |
One other thing regarding resources bears repeating and clarification: the policy of the HIT with respect to releasing resources has always been that all resources are assumed purgeable and are never released (though it's safe for an HIT client to explicitly release resources as soon as that client is certain HIT no longer needs those resources). Although we can make some pretty good guesses at the reasoning behind this policy, it's difficult to explain conclusively because there's not a lot of documentation about the smaller design decisions made during the development of the original Macintosh. In any case, AuntieDialog adopts the same policy in order to avoid creating any additional confusion during your debugging sessions.
Understanding how AuntieDialog uses control IDs is critical. This usage is designed to be as unobtrusive as possible while at the same time enabling you to refer to controls with index values like you would refer to dialog items. If you would like to use other values, you need to be aware of the facilities AuntieDialog provides so you can make an informed decision as to how to choose those values.
When AuntieDialog appends a list of controls to a window, it assigns each control an ID immediately after creating the control. The signature of the ID is kAuntieDialogSignature ('aunt', a value in the Apple-only range).
To choose 'id' field of the ID, AuntieDialog counts the controls which are already in the window (with some exceptions we'll get to in a moment). The first new control gets the count + 1, the second control gets the count + 2, and so on. So, when you add controls to a window which has none, the first control will have ID 1, the second will have ID 2, and so on. If you add controls to a window which already has three controls, the first control will have ID 4, the second 5, and so on.
Any control whose ID signature is not kAuntieDialogSignature does not contribute to the count of controls in a window. You might wonder where such controls would come from, since AuntieDialog always sets the ID signature of the controls it creates to kAuntieDialogSignature. First, the root control does not appear in any dialog item list, is created by AuntieDialog automagically, but is not given kAuntieDialogSignature. Second, controls which are created by other controls, for example the scroll bars created by a list box control, have no ID signature. Since for obscure reasons AuntieDialog cannot predict where in the control hierarchy these controls will appear, it makes no attempt to assign them ID signatures, which is probably what you want anyway.
Note: You can expect standard system controls created by other controls to have no ID signature, but you may encounter custom controls which have other behavior. You may need to set the ID signature of these controls to 0 yourself. If it isn't possible to change the ID signature for such a control, that control is probably not compatible with AuntieDialog. |
AuntieDialog's default control ID is exactly the behavior
you want if you want ID values which correspond to dialog
item index values. With a window full of controls whose IDs
conform to the default behavior of AuntieDialog, you can use
the function GetControlByID
to get a
ControlRef
in much the same manner as you would
use GetDialogItemAsControl
.
But you must accept one more restriction in order to make
this work: If you plan to dispose some controls and append
others &emdash; say, when the user clicks a non-current
tab in a tabs control &emdash; you should only dispose
controls whose IDs are at the end of the range of values for
controls in a given window. This ensures the controls you
later append will acquire a range of IDs which is contiguous
with the controls which remain after the deletion. The
Dialog Manager doesn't allow you to delete items from the
middle of the list, but Control Manager gives you the
freedom to dispose any control at any time, so you need to
be aware of the effect it will have on AuntieDialog.
Deleting controls whose ID is not at the end of the range
for a given window creates the possibility of duplicate IDs,
which would make using GetControlByReference
somewhat less than enjoyable. You need to delete controls in
much the same way as you would shorten a dialog item list
with ShortenDITL.
Sidebar: There are some very credible people, one of whom owns the Control Manager as of this writing, who believe deleting and recreating controls is an inherently risky endeavor. One problem scenario is when a user clicks a non-current tab in a tabs control under adverse conditions such as low memory. If the controls for the tab which is becoming current cannot be created, the operation will fail; the obvious fall-back position is to recreate the controls for the original tab. Unfortunately, this operation may also fail. Now the fallback position is to close the window and apologize to the user. However, at this point we've involved a lot of code to handle exceptional cases, and as most experienced software engineers know, this kind of code tends to get the least testing and is most likely to blow up. The people who concern themselves with this issue think it's much better to create all the controls you'll ever need as you bring up a window and hide and show them as needed. Nothing in AuntieDialog prevents or discourages you from using this technique. And from the system's perspective, this is a non-issue; the system doesn't care why you are deleting and creating controls; the responsibility for pondering this matter falls squarely into your lap. |
OK, the default behavior is all well and good, but suppose you're ready to go beyond simulated dialog item list indexes. If you want control IDs to follow some other logic (say, pointers to instances of a C++ class), you should probably specify a non-NIL control creation function:
typedef pascal OSStatus (*ControlCreationProcPtr) (ControlRef);
You write a function of the above type, and it is called
from inside AppendDialogItemsAsControls
after
each control is created. (The control's ID has already been
assigned according to the default behavior described above.)
Your function decides whether and how to change the control,
including disposing it, based on the control itself and
whatever other criteria you choose.
You can, of course, change the ID of any control (using
SetControlID
), including those created by
AuntieDialog, but you will probably want to make sure the
value is unique with respect to a given window if you want
GetControlByID
to continue working well.
Note that addresses of heap blocks (including those
produced by NewPtr
, NewHandle
,
malloc
, and operator new
) are
unique even beyond the context of a given window, so if you
want to associate the address of a heap block (say, a C++
object pointer) with a control, that address will be
suitable for use as a search key for
GetControlByID
. Be sure, though, that all
controls in a given window have IDs which are unique with
respect to each other. For example, don't expect a C++
object pointer to be a useful control ID if the rest of the
control IDs for the controls in the given window are still
dialog item list indexes. (Not that a C++ object pointer
would ever be as low as a dialog item list index, but you
should still be careful.)
This callback function should not allow C++ exceptions to propagate.
The AuntieDialog package contains functions for creating a window full of controls, for appending lists of controls, for removing child controls, for counting the controls in a window, and for handling events in such a window. The rest is up to you and Window Manager and Control Manager.
OSStatus CountControlsInWindow (WindowRef, UInt16 *);
This function is roughly analagous to
CountDITL
. It counts the number of controls in
a window, excluding the root control and any controls whose
ID signature is not kAuntieDialogSignature. If the window
has no root control, this function fails with an error.
Controls with ID signatures other than
kAuntieDialogSignature are skipped under the assumption that
they are created by other controls, such as the scroll bar
controls created by the list box control, and not by
AuntieDialog. (Keep this is mind if you assign your own ID
values.) You may find this function useful if you adopt the
AuntieDialog convention of storing dialog item list indexes
as control ID values. If you need to know the ID of the
first control which would be added by calling
AppendDialogItemsAsControls
, call
CountControlsInWindow
and add one to the
result.
OSStatus AppendDialogItemsAsControls (short resID, WindowRef, ControlCreationProcPtr);
This function is roughly analgous to
AppendDialogItemList
. The chief difference, of
course, is that this function creates controls, not dialog
items. Another important difference is that this function
makes no attempt to place the new controls anywhere in
particular within the window or resize the window to fit the
new controls. The dialog item list template whose ID you
specify contains the final location of the controls, and
they must fit in the window if you want them to be visible
to the user.
AppendDialogItemsAsControls
is called by
NewAuntieDialog
.
AppendDialogItemsAsControls
inhibits control
drawing and invalidates control regions if the parent window
is visible to prevent some controls from drawing before
others. So, if you have a window for which you must call
GetAuntieDialog
and then
AppendDialogItemsAsControls
before allowing the
user to interact with the window, you won't have to work
around the bizarre non-linear drawing behavior you would
have gotten from Dialog Manager.
AppendDialogItemsAsControls
auto-embeds
controls just as Dialog Manager does.
Unlike Dialog Manager, when
AppendDialogItemsAsControls
creates user pane
controls based on dialog user items, the user pane controls
support embedding, so if you need a user pane control which
doesn't support embedding, you'll need to create an
appropriate control resource.
If you pass a NIL reference provider,
AppendDialogItemsAsControls
will append
controls whose IDs have been assigned in the default
manner.
OSStatus NewAuntieDialog (short resID, WindowRef window, ControlCreationProcPtr);
This function is roughly analgous to
NewDialog
. NewAuntieDialog
calls
AppendDialogItemsAsControls
and is called by
GetAuntieDialog
. The resource ID specifies the
dialog item list resource which is to be used as a template.
This function allows you to create your own window, perhaps
with an API such as CreateNewWindow
, and pass
it to the AuntieDialog package to be populated with
controls. This function will fail if the window already
contains controls.
OSStatus GetAuntieDialog
(short resID, WindowRef behind,
ControlCreationProcPtr, WindowRef *result);
GetAuntieDialog
is roughly analagous to
GetNewDialog
. resID
is the
resource ID of the dialog resource from which you want to
build a window. behind
is the window behind
which you wish the new window to appear. And
result
is where the reference to the newly
created window will be put.
GetAuntieDialog
produces a
WindowRef
, not a DialogRef
. Don't
expect the window that's produced to be recognized by the
Dialog Manager. It's not a dialog. That would defeat the
purpose of AuntieDialog.
GetAuntieDialog
always creates a color
window and ignores any dialog color table resource in favor
of the colors and patterns in the theme the user has chosen.
GetAuntieDialog
also ignores any dialog
extension resource and creates the window as if such a
resource with all its bits set is present, which means you
always get a theme background and you always get theme
controls. (The remaining bits are handled elsewhere in
AuntieDialog or by your program.)
GetAuntieDialog
ignores any extra bits on
the end of the dialog template resource which the Dialog
Manager would have used to align the window. The support for
these bits has never been well-defined or bug-free, and
RepositionWindow
, an API introduced in Mac OS
8.5, is so vastly superior to the old alignment support that
I decided it was better to leave the issue unaddressed.
GetAuntieDialog
always creates the window
initially invisible and only shows it (if the dialog
resource specifies the window is to be shown) after creating
all the controls. This minimizes flicker.
OSStatus DisposeChildControls (ControlRef);
This function disposes the child controls of the given
parent control. This will be useful mostly in conjunction
with AppendDialogItemsAsControls
; you may wish
to delete some controls and append some others, for example
when the user clicks a new tab in a tab control you're using
as a parent control.
This function differs from DisposeControl
in
that DisposeControl
would dispose the parent in
addition to the children.
This function differs from ShortenDITL
not
only in that it operates on controls and not dialog items
but also in that it removes child controls regardless of
where they appeared in the dialog item list before they
became controls. This may create holes in the range of
control IDs. You may want to make sure that the child
controls you dispose appear at the end of the dialog item
list they came from. That way, when you append other
controls, their IDs will be in sequence with the rest of the
controls in the window.